#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <fstream>
#include <stack>
#include "sensor.h"

using namespace std;

#define INF 30000

void getInformation(vector<sensor> &s);
void createData(vector<sensor> &s, int n);
void setSinkNode(vector<sensor> &s);
void linkState(vector<sensor> &s);

int main()
{
    //Simulation variables
    int simTime; //Simulation time that increases by 1
    int totalSimTime; //How long simulation should run
    int numPackets; //Number of initial packets
    int stop; //Value of 1 turns off simulation
    int x;
    int sd;
    //sensor sens1, sens2, sens3; //Sensors
    packet packetFile;
    vector<sensor> s;

    vector<sensor>::iterator sensorIter = s.begin();

    //Initialize sim variables
    cout << "Initiliazing simulation variables" << endl;
    simTime = 0;
    stop = 0;

    //Fills up vectors s with sensor nodes and their information
    getInformation(s);

    //Amount of data for a network to "collect"
    cout << "Enter the number of packets to be put into each node: ";
    cin >> numPackets;

    //Sets a sensor node to be the sink
    setSinkNode(s);

    //Goes through process of finding neighbors for each node
    for(sensorIter = s.begin(); sensorIter != s.end(); sensorIter++)
    {
        // Build neighbor list for each sensor
        sensorIter->getNeighbor(s);
    }

    //Simulation runtime
    cout <<  "Beginning simulation" << endl;
    while(stop == 0)
    {
        simTime++; //Increase simulation time by 1
        createData(s, numPackets); //Right now, it is only intended to be run once to simulate sensor nodes "collecting data"
    }

    cout << "Simulation has stopped" << endl;
    cout << "Total simulation time: " << simTime << endl;

    return 0;
}

void getInformation (vector<sensor> &s)
{
    float xpos, ypos, maxb;
    double maxr;
    string filename;
    int tid, sid, choice, numSensor,numTarget;
    bool linearPower;
    int dataRate;
    int sink;

    // read sensor information
    cout << "Enter sensor file: ";
    cin >> filename;

    ifstream sensorfile (filename.c_str());

    cout << "Enter data rate: ";
    cin >> dataRate;

    cout << "Enter maximum range: ";
    cin >> maxr;

    sink = 0;

    if (sensorfile.is_open())
    {
        sensorfile >> numSensor;
        for(int i=1;i<=numSensor; i++)
        {
            sensorfile >> sid;
            sensorfile >> maxb;
            sensorfile >> xpos;
            sensorfile >> ypos;
            // add the new sensor to vector
            s.push_back(sensor(sid, dataRate, maxb, maxr, xpos, ypos, sink));
        }
        sensorfile.close();
    }
    else
    {
        cout << "Cannot open file " << filename << endl;
    }
}

void createData(vector<sensor> &s, int n)
{
    int x;
    int y;
    packet f;

    for(x=0; x<s.size(); x++)
    {
        for(y=0; y<n; y++)
        {
            f.id = y;
            f.originSens = s[x].getId();
            //f.timeInQueue = 0;
            //f.totalTime = 0;

            s[x].sensorQueue.push(f);
        }
    }
}

void setSinkNode(vector<sensor> &s)
{
    int x;
    int choice;
    float minX;
    float minY;
    float maxX;
    float maxY;
    stack<sensor> minXstack;
    stack<sensor> minYstack;
    stack<sensor> maxXstack;
    stack<sensor> maxYstack;

    //Initialize the variables with the first sensor node in the vector s
    minX = s[0].getx();
    minY = s[0].gety();
    maxX = s[0].getx();
    maxY = s[0].gety();

    //Initialize the different stacks
    minXstack.push(s[0]);
    minYstack.push(s[0]);
    maxXstack.push(s[0]);
    maxYstack.push(s[0]);

    for(x=0; x<s.size(); x++)
    {
        if(minX >= s[x].getx())
        {
            minX = s[x].getx();
            //Keeps the stack keeping track of the min x coordinate updated with the most minimum x coordinate found
            minXstack.pop();
            minXstack.push(s[x]);
        }

        if(minY >= s[x].gety())
        {
            minY = s[x].gety();
            minYstack.pop();
            minYstack.push(s[x]);
        }

        if(maxX <= s[x].getx())
        {
            maxX = s[x].getx();
            maxXstack.pop();
            maxXstack.push(s[x]);
        }

        if(maxY <= s[x].gety())
        {
            maxY = s[x].gety();
            maxYstack.pop();
            maxYstack.push(s[x]);
        }
    }

    //Allows the user to select what type of source node they want to use for the simulation
    cout << "Choose a sink node." << endl;
    cout << endl;
    cout << "0 for a node with minimum x coordinate." << endl;
    cout << "1 for a node with minimum y coordinate." << endl;
    cout << "2 for a node with maximum x coordinate." << endl;
    cout << "3 for a node with maximum y coordinate." << endl;

    cin >> choice;

    if(choice == 0)
    {
        for(x=0; x<s.size(); x++)
        {
            if(s[x].getId() == minXstack.top().getId())
            {
                s[x].setSink(1);
            }
        }
    }

    if(choice == 1)
    {
        for(x=0; x<s.size(); x++)
        {
            if(s[x].getId() == minYstack.top().getId())
            {
                s[x].setSink(1);
            }
        }
    }

    if(choice == 2)
    {
        for(x=0; x<s.size(); x++)
        {
            if(s[x].getId() == maxXstack.top().getId())
            {
                s[x].setSink(1);
            }
        }
    }

    if(choice == 3)
    {
        for(x=0; x<s.size(); x++)
        {
            if(s[x].getId() == maxYstack.top().getId())
            {
                s[x].setSink(1);
            }
        }
    }
}

void linkState(vector<sensor> &s)
{
    int i;
    int j;
    int k;
    vector< vector<int> > tempTable; //Temporary forwarding table
    vector<int> N; //Vector of nodes whose shortest path have already been found

    //Initialization of temporary table
    for(i=0; i<s.size(); i++)
    {
        vector<int> row;
        for(j=0; j<3; j++)
        {
            row.push_back(INF);
        }
        tempTable.push_back(row);
    }

    for(i=0; i<)

    for(k=0; k<s.size(); k++)
    {
        //Select a source node

    }
}
